/*!
 * @file ResourceLoader.c
 * @brief Helper functions for loading embedded resources.
 */
#include <Windows.h>
#include "common.h"

/*!
 * @brief Load a resource from the given module as a raw array of bytes.
 * @param hModule Handle to the module containing the resource.
 * @param uResourceId ID of the resource to load.
 * @param lpType The type of resource being loaded.
 * @param pBuffer Pointer to the buffer that will receive the loaded resource.
 * @param pBufferSize Pointer to the variable that will receive the size of \c pBuffer.
 * @returns Indication of success or failure.
 */
DWORD resource_extract_raw(HMODULE hModule, UINT uResourceId, LPCSTR lpType, LPBYTE* pBuffer, LPDWORD pBufferSize)
{
	DWORD dwResult = FALSE;
	DWORD dwResourceSize = 0;
	LPBYTE pResource = NULL;
	HRSRC hResource = NULL;
	HGLOBAL hResData = NULL;
	LPVOID lpResData = NULL;

	*pBuffer = NULL;
	*pBufferSize = 0;

	do
	{
		if ((hResource = FindResourceA(hModule, MAKEINTRESOURCEA(uResourceId), lpType)) == NULL) {
			dwResult = GetLastError();
			dprintf("[RES] Unable to find resource %d type %s", uResourceId, lpType);
			break;
		}

		if ((dwResourceSize = SizeofResource(hModule, hResource)) == 0) {
			dwResult = GetLastError();
			dprintf("[RES] Unable to find resource size for %d type %s", uResourceId, lpType);
			break;
		}

		if ((pResource = (LPBYTE)malloc(dwResourceSize)) == NULL) {
			dwResult = ERROR_NOT_ENOUGH_MEMORY;
			dprintf("[RES] Unable to allocate memory for resource %d type %s size %u", uResourceId, lpType, dwResourceSize);
			break;
		}

		if ((hResData = LoadResource(hModule, hResource)) == NULL) {
			dwResult = GetLastError();
			dprintf("[RES] Unable to load resource for %d type %s", uResourceId, lpType);
			break;
		}

		if ((lpResData = LockResource(hResData)) == NULL) {
			dwResult = GetLastError();
			dprintf("[RES] Unable to lock resource for %d type %s", uResourceId, lpType);
			break;
		}

		memcpy_s(pResource, dwResourceSize, lpResData, dwResourceSize);

		// Locked resource don't need to be unlocked. If we get here, we've won!
		dwResult = ERROR_SUCCESS;
		*pBuffer = lpResData;
		*pBufferSize = dwResourceSize;

	} while (0);

	if (dwResult != ERROR_SUCCESS && pResource != NULL) {
		free(pResource);
	}

	return dwResult;
}

/*!
 * @brief Free up memory that was allocated when loading the resource.
 * @param lpBuffer Pointer to the allocated buffer.
 * @returns \c ERROR_SUCCESS
 */
DWORD resource_destroy(LPBYTE lpBuffer)
{
	if (lpBuffer != NULL)
	{
		free(lpBuffer);
	}
	return ERROR_SUCCESS;
}